package com.sskj.gateway.event;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sskj.common.dto.DeviceTelemetry;
import com.sskj.common.enums.DeviceNetProtocolEnum;
import com.sskj.common.enums.DeviceTelemetryTypeEnum;
import com.sskj.gateway.service.IDeviceDataService;
import com.sskj.gateway.session.DeviceSession;
import com.sskj.gateway.session.DeviceSessionManager;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.time.Instant;
import java.util.*;

@Slf4j
@Component
public class DeviceMessageListener {

    @Autowired
    private IDeviceDataService deviceDataService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private DeviceSessionManager deviceSessionManager;

    @EventListener
    @Async // 可异步处理，避免阻塞 Netty 线程
    public void handleDeviceMessage(DeviceMessageEvent event) {
        DeviceTelemetry deviceTelemetry = event.getMessage();
        log.info("收到设备数据: {}", deviceTelemetry.getDeviceCode());

        if (deviceTelemetry.getType() == DeviceTelemetryTypeEnum.PROPERTY.getType()) {
            handleThingsModelMapping(deviceTelemetry);
            deviceDataService.addOrUpdateShadow(deviceTelemetry);
        }
        if (deviceTelemetry.getType() == DeviceTelemetryTypeEnum.ONLINE.getType()) {
            handleDeviceOnline(deviceTelemetry, event.getChannelHandlerContext());
        }
        if (deviceTelemetry.getType() == DeviceTelemetryTypeEnum.OFFLINE.getType()) {
            handleDeviceOffline(deviceTelemetry, event.getChannelHandlerContext());
        }

        // 1. 存储
//        deviceDataService.save(msg);

        // 2. 触发规则引擎
        // ruleEngine.trigger(msg);

        // 3. 推送 WebSocket
        // webSocketService.push(msg);

        // 4. 转发到 Kafka
        // kafkaTemplate.send("device-topic", msg);
    }

    /**
     * 处理物模型映射关系
     * @param deviceTelemetry 实例
     */
    private void handleThingsModelMapping(DeviceTelemetry deviceTelemetry) {
        // 查询对应的物模型定义
        String thingsModelStr = "{\"modelId\":\"SimpleDevice\",\"version\":\"1.0.0\",\"properties\":[{\"name\":\"heartbeat\",\"identifier\":\"heartbeat\",\"dataType\":\"int\",\"unit\":\"\",\"description\":\"设备心跳信号，表示设备在线状态。通常为时间戳或递增计数器。\",\"readOnly\":true,\"required\":false}],\"events\":[],\"services\":[]}\n";
        try {
            // 2. 解析物模型 JSON
            JsonNode modelRoot = objectMapper.readTree(thingsModelStr);
            JsonNode propertiesNode = modelRoot.get("properties");

            if (propertiesNode == null || !propertiesNode.isArray()) {
                log.warn("物模型中未定义 properties 或格式错误。设备CODE={}", deviceTelemetry.getDeviceCode());
                return;
            }

            Set<String> validIdentifiers = new HashSet<>();
            Map<String, JsonNode> propertySchemaMap = new HashMap<>();
            for (JsonNode prop : propertiesNode) {
                String identifier = prop.get("identifier").asText();
                if (StringUtils.hasText(identifier)) {
                    validIdentifiers.add(identifier);
                    propertySchemaMap.put(identifier, prop);
                }
            }

            Map<String, Object> rawProperties = deviceTelemetry.getProperties();
            if (rawProperties == null || rawProperties.isEmpty()) {
                log.warn("设备未上报任何属性数据");
                return;
            }

            Map<String, Object> validatedProperties = new HashMap<>();
            List<String> invalidKeys = new ArrayList<>();
            for (Map.Entry<String, Object> entry : rawProperties.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();

                if (!validIdentifiers.contains(key)) {
                    invalidKeys.add(key);
                    continue; // 忽略非法属性
                }

                JsonNode schema = propertySchemaMap.get(key);
                Object validatedValue = validateAndConvertValue(key, value, schema);

                if (validatedValue != null) {
                    validatedProperties.put(key, validatedValue);
                } else {
                    log.warn("属性 [{}] 值校验失败:{}", key, value);
                }
            }

            if (!invalidKeys.isEmpty()) {
                log.warn("忽略未知属性:{} ", invalidKeys);
            }

            deviceTelemetry.setProperties(validatedProperties);
        } catch (JsonProcessingException e) {
            log.error("解析物模型失败。异常信息：{}", e.getMessage());
        } catch (Exception e) {
            log.error("处理物模型映射时发生异常。异常信息：{}", e.getMessage());
        }
    }

    /**
     * 处理设备上线事件
     */
    private void handleDeviceOnline(DeviceTelemetry telemetry, ChannelHandlerContext channelHandlerContext) {
        // 保存会话信息
        DeviceSession deviceSession = new DeviceSession();
        deviceSession.setDeviceCode(telemetry.getDeviceCode());
        deviceSession.setProtocol(DeviceNetProtocolEnum.TCP.getProtocol());

        Channel channel = channelHandlerContext.channel();
        deviceSession.setChannel(channel);
        deviceSession.setClientIp(channel.remoteAddress().toString());

        deviceSessionManager.registerSession(telemetry.getDeviceCode(), deviceSession);

        // 处理设备上线的相关逻辑
        deviceDataService.online(telemetry);
//        String deviceCode = telemetry.getDeviceCode();
//
//        // 1. 更新设备状态为在线（可存入 Redis 或 DB）
//        deviceStatusService.updateStatus(deviceCode, DeviceStatus.ONLINE);
//        deviceStatusService.updateLastOnlineTime(deviceCode, System.currentTimeMillis());
//
//        // 2. 初始化设备影子（如果还不存在）
//        //    确保影子存在，避免后续属性更新时没有基础数据
//        deviceDataService.initDeviceShadowIfAbsent(telemetry);
    }

    /**
     * 处理设备下线事件
     */
    private void handleDeviceOffline(DeviceTelemetry telemetry, ChannelHandlerContext channelHandlerContext) {
        deviceDataService.offline(telemetry);
//        String deviceCode = telemetry.getDeviceCode();
//
//        // 1. 更新设备状态为离线
//        deviceStatusService.updateStatus(deviceCode, DeviceStatus.OFFLINE);
//        deviceStatusService.updateLastOfflineTime(deviceCode, System.currentTimeMillis());
    }

    /**
     * 校验并转换值类型（根据 dataType）
     * @param key 键名
     * @param value 值
     * @param schema 模
     * @return 返回值
     */
    private Object validateAndConvertValue(String key, Object value, JsonNode schema) {
        String dataType = schema.get("dataType").asText("string");
        try {
            switch (dataType.toLowerCase()) {
                case "int":
                case "integer":
                    if (value instanceof Number) {
                        return ((Number) value).longValue();
                    } else if (value instanceof String) {
                        return Long.parseLong((String) value);
                    } else {
                        return 0;
                    }
                case "float":
                case "double":
                    if (value instanceof Number) {
                        return ((Number) value).doubleValue();
                    } else if (value instanceof String) {
                        return Double.parseDouble((String) value);
                    } else {
                        return 0;
                    }
                case "bool":
                case "boolean":
                    if (value instanceof Boolean) {
                        return value;
                    } else if (value instanceof String) {
                        return Boolean.parseBoolean((String) value);
                    } else {
                        return null;
                    }
                case "string":
                    return value != null ? value.toString() : "";
                case "enum":
                    int enumValue;
                    try {
                        enumValue = Integer.parseInt(value.toString());
                    } catch (NumberFormatException e) {
                        return null;
                    }

                    JsonNode enumNode = schema.get("enum");
                    if (enumNode == null || !enumNode.isArray() || enumNode.isEmpty()) {
                        return null;
                    }

                    for (JsonNode item : enumNode) {
                        if (item.has("value") && item.get("value").isInt()) {
                            if (item.get("value").asInt() == enumValue) {
                                return enumValue;
                            }
                        }
                    }
                    return "";
                case "date":
                    if (value instanceof Long || (value instanceof String && ((String) value).matches("\\d+"))) {
                        long timestamp = Long.parseLong(value.toString());
                        return Instant.ofEpochMilli(timestamp).toString(); // 返回 ISO8601 字符串
                    }
                    break;
                case "struct":
                    if (value instanceof Map) {
                        Map<String, Object> struct = (Map<String, Object>) value;
                        JsonNode structSchema = schema.get("struct");
                        if (structSchema != null && structSchema.isObject()) {
                            Map<String, Object> validatedStruct = new HashMap<>();
                            structSchema.fields().forEachRemaining(field -> {
                                String fieldId = field.getKey();
                                Object fieldValue = struct.get(fieldId);
                                JsonNode fieldSchema = field.getValue();
                                validatedStruct.put(fieldId, validateAndConvertValue(fieldId, fieldValue, fieldSchema));
                            });
                            return validatedStruct;
                        }
                    }
                    break;
                default:
                    return value != null ? value.toString() : null;
            }
        } catch (Exception e) {
            log.warn("属性 [{}] 类型转换失败: {}", key, e.getMessage());
        }

        return null;
    }
}
